#include "SemanticNodeExpression.h"

#include "main2.h"

/**
 *  @fn	SemanticNodeExpression::SemanticNodeExpression(const SyntaxTreeNode &expressionNode,
 *  	const SemanticNode *parent)
 *
 *  @brief	Constructs an expression by breaking it up into a number of single-operation commands.
 *
 *  @author	Nikola Novak.
 *  @date	6/6/2009.
 *
 *  @param	expressionNode	Syntax node at the base of the expression which initializes this field.
 *  @param	parent	Parent semantic node.
 */
SemanticNodeExpression::SemanticNodeExpression(const SyntaxTreeNode *expressionNode, SemanticNode *parent) : SemanticNode(parent), ValueType(getNextUniqueID()) {
	flatSyntaxNode = copyNode(expressionNode);
	connect(expressionNode, flatSyntaxNode);
}
/**
 *  @fn	void SemanticNodeExpression::makeFlat(void)
 *
 *  @brief	Makes this expression flat.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 */
void SemanticNodeExpression::makeFlat(void) {
	flattenExcessProductions(flatSyntaxNode);
	removeEpsilonProductions(flatSyntaxNode);
	removeExcessNodes(flatSyntaxNode, NULL, -1);
	if (flatSyntaxNode->Nodes->GetCount() == 1) {
		SyntaxTreeNode *oldTop = flatSyntaxNode;
		flatSyntaxNode = oldTop->Nodes->GetData(0);
		oldTop->Nodes->RemoveAtWithoutFreeMem(0);
		delete oldTop;
	}
	flattenExpression(flatSyntaxNode, 0);
}
/**
 *  @fn	void SemanticNodeExpression::connect(const SyntaxTreeNode *expressionNode,
 *  	SyntaxTreeNode *flatExpressionNode)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/16/2009.
 *
 *  @param	expressionNode		.
 *  @param	flatExpressionNode	.
 */
void SemanticNodeExpression::connect(const SyntaxTreeNode *expressionNode, SyntaxTreeNode *flatExpressionNode) {
	if (isValueNode(expressionNode)) connector[expressionNode] = flatExpressionNode;
	for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x) {
		connect(expressionNode->Nodes->GetData(x), flatExpressionNode->Nodes->GetData(x));
	}
}
/**
 *  @fn	void SemanticNodeExpression::flattenExpression(SyntaxTreeNode *expressionNode)
 *
 *  @brief	Flattens the semi-flattened expression.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	expressionNode	The semi-flat expression node.
 */
int SemanticNodeExpression::flattenExpression(SyntaxTreeNode *expressionNode, int uniqueVarIndex) {
	//int[] nodeVals = new int[expressionNode->Nodes->GetCount()];
	//if (!canWorkWith(expressionNode)) {
	//	for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x) {
	//		nodeVals[x] = flattenExpression(expressionNode->Nodes->GetData(x), uniqueVarIndex);
	//		uniqueVarIndex = nodeVals[x] + 1;
	//	}
	//}
	//AtomicStatement::Action a = parseNodes(expressionNode);
	return uniqueVarIndex;
}
/**
 *  @fn	AtomicStatement::Action SemanticNodeExpression::parseNodes(SyntaxTreeNode *expressionNode)
 *
 *  @brief	Parse nodes.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	expressionNode	If non-null, the expression node.
 *
 *  @return	Parsed action.
 */
AtomicStatement::Action SemanticNodeExpression::parseNodes(SyntaxTreeNode *expressionNode) {
	return AtomicStatement::LogicNot;
}
/**
 *  @fn	bool SemanticNodeExpression::canWorkWith(SyntaxTreeNode *expressionNode)
 *
 *  @brief	Queries if we can work with 'expressionNode'.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	expressionNode	The semi-flat expression node.
 *
 *  @return	True if all child nodes are flat.
 */
bool SemanticNodeExpression::canWorkWith(SyntaxTreeNode *expressionNode) {
	for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x) {
		if (expressionNode->Nodes->GetData(x)->LexUnitID == -1) return false;
	}
	return true;
}
/**
 *  @fn	void SemanticNodeExpression::removeEpsilonProductions(SyntaxTreeNode *expressionNode)
 *
 *  @brief	Removes the epsilon productions in the expressionNode subtree of the syntax tree.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	expressionNode	The expression node.
 */
void SemanticNodeExpression::removeEpsilonProductions(SyntaxTreeNode *expressionNode) {
	if (expressionNode->Production == Gr_Expression9__Value) return;
	for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x) {
		SyntaxTreeNode *stn = expressionNode->Nodes->GetData(x);
		if (stn->Nodes->GetCount() == 0 && stn->LexUnitID == -1) expressionNode->Nodes->RemoveAt(x--);
		else removeEpsilonProductions(stn);
	}
}
/**
 *  @fn	void SemanticNodeExpression::removeExcessNodes(SyntaxTreeNode &expressionNode)
 *
 *  @brief	Removes all nodes which have exactly one non-terminal child node remaining. WARNING: THIS METHOD MAKES CHANGES ON THE SYNTAX TREE
	*         (EXPRESSION NODE AND ALL CHILD NODES)! CHILDREN WILL NO LONGER POINT TO THEIR PARENTS!
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param [in,out]	expressionNode	the expression node.
 */
int SemanticNodeExpression::removeExcessNodes(SyntaxTreeNode *expressionNode, SyntaxTreeNode *parentNode, int index) {
	if (isValueNode(expressionNode))	return index;
	// if parent is null then no removing will take place
	if (parentNode != NULL) {
		// if this node has one non-terminal child then
		if (expressionNode->Nodes->GetCount() == 1) {
			// rescue child
			SyntaxTreeNode *childNode = expressionNode->Nodes->GetData(0);
			// detach child from this node
			expressionNode->Nodes->RemoveAtWithoutFreeMem(0);
			// detach this node from parent
			parentNode->Nodes->RemoveAtWithoutFreeMem(index);
			// attach child node to parent
			parentNode->Nodes->Insert(childNode, index);
			// delete this node
			delete expressionNode;
			// go back and iterate on parent
			return index - 1;
		}
	}
	// if parent is null or this node has more than one child
	// iterate through all nodes in expressionNode and remove their excess nodes
 for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x)
		x =	removeExcessNodes(expressionNode->Nodes->GetData(x), expressionNode, x);
	return index;
}
/**
 *  @fn	void SemanticNodeExpression::flattenExcessProductions(SyntaxTreeNode &expressionNode)
 *
 *  @brief	Pulls up child nodes of nodes of type ExpressionXAdd and ExpressionXAdds to their
	*         parent nodes. WARNING: THIS METHOD MAKES CHANGES ON THE SYNTAX TREE
	*         (EXPRESSION NODE AND ALL CHILD NODES)! CHILDREN WILL NO LONGER POINT TO THEIR PARENTS!
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param [in,out]	expressionNode	The expression node.
 */
void SemanticNodeExpression::flattenExcessProductions(SyntaxTreeNode *expressionNode) {
	if (expressionNode->Production == Gr_Expression9__Value) return;
	for (int x = 0; x < expressionNode->Nodes->GetCount(); ++x) {
		SyntaxTreeNode *stn = expressionNode->Nodes->GetData(x);
		Grammar prod = stn->Production;
		switch(prod) {
			case Gr_ExpressionAdds__ExpressionAdd_ExpressionAdds:
			case Gr_ExpressionAdd__opOr_Expression2:
			case Gr_Expression2Adds__Expression2Add_Expression2Adds:
			case Gr_Expression3Adds__Expression3Add_Expression3Adds:
			case Gr_Expression6Adds__Expression6Add_Expression6Adds:
			case Gr_Expression7Adds__Expression7Add_Expression7Adds:
			case Gr_Expression6Add__opAdd_Expression7:
			case Gr_Expression6Add__opSub_Expression7:
			case Gr_Expression7Add__opDiv_Expression8:
			case Gr_Expression7Add__opMod_Expression8:
			case Gr_Expression7Add__opMul_Expression8:
			case Gr_Expression3Add__opAnd_Expression4:
			case Gr_Expression4__opNot_Expression4:
			case Gr_Expression8__Expression9_opExp_Expression8:
			case Gr_Expression9__opAdd_Expression9:
			case Gr_Expression9__opSub_Expression9:
				// remove this node from expressionNode
				expressionNode->Nodes->RemoveAtWithoutFreeMem(x);
				// pull children up
				for (int y = 0; y < stn->Nodes->GetCount(); ++y)	expressionNode->Nodes->Insert(stn->Nodes->GetData(y), x + y);
				// trackback
				--x;
				// remove children from the excess node
			 for (int y = 0; y < stn->Nodes->GetCount(); ++y) stn->Nodes->RemoveAtWithoutFreeMem(y);
				// release the excess node
				delete stn;
				break;
			default:
				flattenExcessProductions(stn);
				break;
		}
	}
}

/**
 *  @fn	std::string SemanticNodeExpression::toDebugString(int tab)
 *
 *  @brief	Writes this object as a debug string.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	tab	The tab.
 *
 *  @return	This object as a std::string.
 */
std::string SemanticNodeExpression::toDebugString(int tab) {
	std::ostringstream res;
	res << convDebug(tab, flatSyntaxNode);
	return res.str();
}

std::string SemanticNodeExpression::convDebug(int tab, SyntaxTreeNode *node) {
	std::ostringstream res;
	if (isValueNode(node)) {
		NodeInfo *ni = equivalentNode[node];
		if (ni == NULL) {
			for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
			res << "// ToDo" << std::endl;
		}	else {
			if (ni->nodeType == Value) {
				for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
				res << "Value = " << ni->name << std::endl;
			}	else if (ni->nodeType == NullNode) {
				for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
				res << "Value = null" << std::endl;
			} else {
		  SemanticNode *n = ni->node;
				res << n->toDebugString(tab + 1);
		 }
		}
	} else {
		for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
	 if (node->LexUnitID == -1)	res << CompilerData->SyntaxTree->ConvertProductionToString(node->Production) << std::endl;
	 else	res << CompilerData->Units->GetLexicUnitString(node->LexUnitID) << std::endl;
	 for (int x = 0; x < node->Nodes->GetCount(); ++x) {
	 	res << convDebug(tab + 1, node->Nodes->GetData(x));
	 }
	}
	return res.str();
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeInstanceOf *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeInstanceOf *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNInstanceOf);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNode *node, const SyntaxTreeNode *reference,
 *  	Semantics type)
 *
 *  @brief	Adds a value.
 *
 *  @author	Nikola Novak
 *  @date	6/16/2009
 *
 *  @param	node		If non-null, the node.
 *  @param	reference	If non-null, the reference.
 *  @param	type		The type.
 */
void SemanticNodeExpression::addValue(SemanticNode *node, const SyntaxTreeNode *reference, Semantics type) {
	NodeInfo *a = new NodeInfo();
	a->node = node;
	a->nodeType = type;
	equivalentNode[connector[reference]] = a;
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeMethodCall *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeMethodCall *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNMethodCall);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeCreateArray *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeCreateArray *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNCreateArray);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeConstructObject *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeConstructObject *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNConstructObject);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeCast *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeCast *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNCast);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeVariableName *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeVariableName *node, const SyntaxTreeNode *reference) {
	addValue(node, reference, SNVariableName);
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SyntaxTreeNode *node)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(const SyntaxTreeNode *node) {
	if (node->Production == Gr_Value__LITERAL) {
	 NodeInfo *a = new NodeInfo();
	 a->node = NULL;
	 a->nodeType = Value;
	a->name = CompilerData->Units->GetLexicUnitString(&CompilerData->Units->GetLexicUnit(node->Nodes->GetData(0)->LexUnitID));
	 equivalentNode[connector[node]] = a;
	} else if (node->Production == Gr_Value__null) {
		NodeInfo *a = new NodeInfo();
	 a->node = NULL;
	 a->nodeType = NullNode;
	 equivalentNode[connector[node]] = a;
	} else { /* Cannot happen. */ }
}
/**
 *  @fn	void SemanticNodeExpression::addValue(SemanticNodeExpression *node, SyntaxTreeNode *reference)
 *
 *  @brief	.
 *
 *  @author	Nikola Novak.
 *  @date	6/15/2009.
 *
 *  @param	node	.
 */
void SemanticNodeExpression::addValue(SemanticNodeExpression *node, const SyntaxTreeNode *reference) {
	//SyntaxTreeNode *stn = connector[reference];
	//*stn = *node->flatSyntaxNode;
	//mergeTablesWith(node, stn);
	//// ToDo: addStatements(node->statements);
	addValue(node, reference, SNBracketedExpression);
}
/**
 *  @fn	void SemanticNodeExpression::mergeTablesWith(const SemanticNodeExpression *node)
 *
 *  @brief	Merges connect and equivalentNode tables with another expression node.
 *
 *  @author	Nikola Novak.
 *  @date	6/17/2009.
 *
 *  @param	node	A node to merge the tables with.
 */
void SemanticNodeExpression::mergeTablesWith(SemanticNodeExpression *node, SyntaxTreeNode *myRef) {
	connector.insert(node->connector.begin(), node->connector.end());
	if (node->connector.size() == 1) {
		std::map<const SyntaxTreeNode *, SyntaxTreeNode *>::iterator it = node->connector.begin();
		equivalentNode[myRef] = node->equivalentNode[(*it).second];
		return;
	}
	equivalentNode.insert(node->equivalentNode.begin(), node->equivalentNode.end());
}
